﻿using Microsoft.Win32;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
using WindowService;

namespace ConsoleProcessMonitor
{
    public class Service // : ServiceBase
    {
        
        protected Ini ini = null;
        VersionHelper versionHelper = null;
        //进程管理与上送定时器
        private System.Timers.Timer processTimer = null;
        //软件自动更新定时器
        private System.Timers.Timer upgradeTimer = null;
        private static string serviceName = "CProcessMonitor";
        public string currentDirectory = Environment.CurrentDirectory;
        public string mac = "";
        protected void initLog()
        {
            try
            {
                //获取默认服务程序地址
                currentDirectory = getCurrentDirectory();

                ini = new Ini(currentDirectory, @"config.ini", this.getDefaultConfigIniContent());
                string logSavePath = this.ini.ReadValue("Setting", "LogSavePath") as string;
                Log.SavePath = logSavePath == "" ? currentDirectory : logSavePath;
                Log.needTrace = getShowTrace();
            }
            catch (Exception e)
            {
                Log.WriteLog("MainService Init Log failed, error: " + e.Message, LogType.Error);
            }
        }
        protected void initService()
        {
            try
            {
                VersionHelper.SavePath = Log.SavePath;
                versionHelper = new VersionHelper(ini);

                //获取mac地址
                Wmi wmi = new Wmi();
                mac = wmi.getMac();

                Log.WriteLog("MainService Start Service", LogType.Info);
            }
            catch (Exception e)
            {
                Log.WriteLog("MainService Init Service failed, error: " + e.Message, LogType.Error);
            }
        }

        protected void StartTimer(){
            Log.WriteLog("MainService ProcessTimer Start", LogType.Info);
            processTimer = new System.Timers.Timer();
            processTimer.Interval = getProcessInterval();
            processTimer.Elapsed += new System.Timers.ElapsedEventHandler(ProcessTimerEvent);
            processTimer.AutoReset = true;
            processTimer.Enabled = true;

            Log.WriteLog("MainService UpgradeTimer Start", LogType.Info);
            upgradeTimer = new System.Timers.Timer();
            upgradeTimer.Interval = getUpgradeInterval();
            upgradeTimer.Elapsed += new System.Timers.ElapsedEventHandler(UpgradeTimerEvent);
            upgradeTimer.AutoReset = true;
            upgradeTimer.Enabled = true;
        }
        protected void StopTimer()
        {
            processTimer.Stop();
            upgradeTimer.Stop();
            Log.WriteLog("MainService All Timer was Stoped", LogType.Info);
        }
        //运行关键进程，上送进程列表
        public void ProcessTimerEvent(object source, System.Timers.ElapsedEventArgs args)
        {
            Log.WriteLog("MainService ProcessTimer Ticking...", LogType.Trace);
            Process[] runningProcesses = null;
            ArrayList processList = ini.ReadValues("ProcessList", null);

            for (int i = 0; i < processList.Count; i++)
            {
                bool isRunning = false;
                //当前系统进程列表
                runningProcesses = Process.GetProcesses();
                for (int j = 0; j < runningProcesses.Length; j++)
                {
                    if (processList[i].ToString() == runningProcesses[j].ProcessName)
                    {
                        Log.WriteLog("MainService Check Process Run status, \"" + processList[i].ToString() + "\" is Running", LogType.Trace);
                        isRunning = true;
                    }
                }

                //如果配置的进程未运行，则直接运行
                if (!isRunning)
                {
                    Log.WriteLog("MainService Have some Processes is not Running", LogType.Trace);
                    try
                    {
                        Log.WriteLog("MainService Process " + processList[i].ToString() + " is not running", LogType.Info);
                        string runProcessArg = ini.ReadValue("ProcessList", (string)processList[i]);
                        int spacePosition = runProcessArg.IndexOf(" ");
                        string[] processArguments = new string[2];
                        if (spacePosition != -1)
                        {
                            processArguments[0] = runProcessArg.Substring(0, spacePosition);
                            processArguments[1] = runProcessArg.Substring(spacePosition);
                            if (processArguments[1].Length > 0)
                            {
                                CreateProcessAsUserWrapper.Start(processArguments);
                                //Process.Start(runProcess, runArgs);
                                Log.WriteLog("MainService Process " + processList[i].ToString() + " run with args \"" + runProcessArg + "\"", LogType.Info);
                                continue;
                            }
                        }
                        processArguments[0] = runProcessArg;
                        processArguments[1] = null;
                        CreateProcessAsUserWrapper.Start(processArguments);
                        //Process.Start(runProcessArg);
                        Log.WriteLog("MainService Process " + processList[i].ToString() + " run with args \"" + runProcessArg + "\"", LogType.Info);
                    }
                    catch (Exception e)
                    {
                        Log.WriteLog("MainService Process " + processList[i].ToString() + " is not run, the reason is " + e.Message, LogType.Error);
                    }
                }
            }

            //发送进程列表参数
            List<string> processes = new List<string>();
            //当前系统进程列表
            runningProcesses = Process.GetProcesses();
            for (int j = 0; j < runningProcesses.Length; j++)
            {
                processes.Add(runningProcesses[j].ProcessName);
            }

            //判断是否进入桌面，即不存在进程 logonUI
            string logonUIProcessName = getLogonProcessName();
            string isInDeskTop = (processes.Contains(logonUIProcessName)) ? "0" : "1";
            //保存POST参数
            IDictionary<string, string> postParams = new Dictionary<string, string>();
            postParams.Add("mac", mac);
            postParams.Add("processList", string.Join(",", processes.ToArray()));
            postParams.Add("isInDesktop", isInDeskTop);
            //请求配置的进程列表接收端口
            HttpWebResponseUtility.CreatePostHttpResponse(getProcessReportURL(), postParams, 2000, null, Encoding.UTF8, null);
        }
        //检查更新
        public void UpgradeTimerEvent(object source, System.Timers.ElapsedEventArgs args)
        {
            Log.WriteLog("MainService UpgradeTimer Ticking...", LogType.Trace);

            if (DateTime.Now.ToString("HH:mm:ss") == getUpgradeTime())
            {
                Log.WriteLog("MainService Start upgrade", LogType.Trace);
                //保存HTTP GET 参数
                string parameters = @"?mac=" + mac;
                string response = HttpWebResponseUtility.CreateGetHttpResponse(getUpgradeURL() + parameters, 200000, Encoding.UTF8, null, null);
                if (response != null)
                {
                    try
                    {
                        JObject obj = JObject.Parse(response);
                        if (obj["errcode"].ToString() == "0")
                        {
                            JObject dataJson = (JObject)obj["data"];
                            versionHelper.upgrade(dataJson);
                        }
                    }
                    catch (Exception e)
                    {
                        Log.WriteLog("MainService try to parse upgrade data failed, error: " + e.Message , LogType.Error);
                    }
                }
            }
            else
            {
                Log.WriteLog("MainService Will not check upgrade, beause Upgrade time:[" + getUpgradeTime() + "] is not eq Now time:[" + DateTime.Now.ToString("HH:mm:ss") + "]", LogType.Trace);
                Console.WriteLine(DateTime.Now.ToString("HH:mm:ss"));
            }
        }
        //开启调试日志
        private bool getShowTrace()
        {
            return ini.getStrConfig("Setting", "ShowTrace", "true") == "true" ? true : false;
        }
        //获取升级定时器周期
        private int getUpgradeInterval()
        {
            //每秒检查一下升级时间是否已到达
            return 1000;
        }
        //获取进程列表上送周期
        private int getProcessInterval()
        {
            return Math.Abs(ini.getIntConfig("Setting", "ProcessPutInterval", 10, 65535, 10) * 1000);
        }
        //获取上送进程列表URL
        private string getProcessReportURL()
        {
            return ini.getStrConfig("Setting", "ProcessReportURL", @"http://test.local/process_list");
        }
        //获取升级列表URL
        private string getUpgradeURL()
        {
            return ini.getStrConfig("Setting", "UpgradeURL", @"http://test.local/upgrade_list");
        }
        private string getUpgradeTime()
        {
            return ini.getTimeConfig("Setting", "UpgradeTime");
        }
        //获取默认配置信息
        protected string getDefaultConfigIniContent()
        {
            return ";进程监控器配置\r\n\r\n[Setting]"
                + "\r\n;是否开启调试日志\r\nShowTrace=true"
                + "\r\n\r\n;日志保存地址(默认:" + currentDirectory + ")\r\nLogSavePath=" + currentDirectory 
                + "\r\n;进程列表上送时间间隔(10s-65535s)\r\nProcessPutInterval=10"
                + "\r\n;每个升级程序运行的最大超时时间（60-65535s）,超时后将强制停止升级\r\nOneUpgradeMaxTimeOut=60"
                + "\r\n;每个升级程序运行结束后等待的空闲时间(0-65535s)，即当一个升级完成后，下一个升级将在多少s后开始升级\r\nOneUpgradeDoneSleepTime=5"
                + "\r\n;所有升级完成后，进行系统重启的等待时间(10-65535s)\r\nUpgradeDoneSleepTime=30"
                + "\r\n;检查升级时间（默认：00:00:00）\r\nUpgradeTime=00:00:00"
                + "\r\n;进程列表上送URL地址\r\nProcessReportURL=http://api.device.local/user/process_list"
                + "\r\n;升级获取URL地址\r\nUpgradeURL=http://api.device.local/user/upgrade_list"
                + "\r\n\r\n;进程列表\r\n[ProcessList]\r\n;进程名称=进程启动全路径 启动参数\r\ncmd=C:\\Windows\\System32\\cmd.exe /t:4A\r\nnotepad=notepad.exe";
        }
        //获取是否登录到桌面的进程名称
        private string getLogonProcessName()
        {
            string logonProcessName = "LogonUI";
            RegistryHelper registryHelper = new RegistryHelper();
            logonProcessName = registryHelper.GetRegistryData(Registry.LocalMachine, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", "UIHost");
            logonProcessName = logonProcessName == "" ? "LogonUI" : logonProcessName;

            return logonProcessName;
        }
        //获取当前服务程序地址
        private string getCurrentDirectory()
        {
            string defaultDir = currentDirectory;
            string currAppDir = "";
            try
            {
                RegistryHelper registryHelper = new RegistryHelper();
                currAppDir = registryHelper.GetRegistryData(Registry.LocalMachine, "SYSTEM\\CurrentControlSet\\Services\\" + serviceName, "ImagePath");
                currAppDir = currAppDir != "" ? currAppDir : defaultDir + "\\" + serviceName + ".exe";
                currAppDir = currAppDir.Replace("\"", "");
                currAppDir = currAppDir.Replace(@"%SystemRoot%\system32", Environment.GetFolderPath(Environment.SpecialFolder.System));

                if (currAppDir.IndexOf(" ") > 0)
                {
                    currAppDir = currAppDir.Substring(0, currAppDir.IndexOf(" "));
                }
                currAppDir = System.IO.Path.GetDirectoryName(currAppDir) + @"\";
            }
            catch (Exception e)
            {
                Log.WriteLog("MainService Get current directory:" + "SYSTEM\\CurrentControlSet\\Services\\" + serviceName + " error:" + e.Message, LogType.Error);
                currAppDir = defaultDir;
            }
            Log.WriteLog("MainService Get Current Directory:" + currAppDir, LogType.Trace);
            
            return currAppDir;
        }
    }
}
